#ifndef __UVSETTINGS_H
#define __UVSETTINGS_H

#include <cstring>
#include <string>
#include <map>
#include <vector>

#define FLAG_PREFIX "--"

#define SETTINGS_IS_FLAG(str) \
    (std::strncmp(str, FLAG_PREFIX, std::strlen(FLAG_PREFIX)) == 0)

#define SETTINGS_IS_USING_EQUALS(str) \
    (std::strchr(str, '=') != NULL)

namespace uv {
namespace settings {

/**
 * A Value object is used to capture a command line argument into an easily
 * accessible object. When created, a tag is provided. The object will then
 * attain its value accepting the following formats:
 * <ul>
 *   <li>--tag value</li>
 *   <li>--tag=value</li>
 * </ul>
 */
template <class T>
class Value {
public:
    /**
     * Create a new command line argument value.
     *
     * @param _default_value The default value of the object should the tag
     *            not be used in the command line argument list.
     * @param _tag The tag value used for finding the value.
     * @param _description A description string used to create a help menu.
     */
    Value(T _default_value, std::string _tag, std::string _description);

    /**
     * Get the current value of the object. If the value was not set in the
     * command line or overridden then the default value is returned.
     *
     * @return The value currently stored in the object.
     */
    T getValue();

    /**
     * Sets a new override value for the object.
     *
     * @param _value The new value to be used for this object.
     */
    void setOverride(T _value);

    /**
     * Reset the object to its default value.
     */
    void reset();

    /**
     * @return The help string associated with this object.
     */
    std::string toString();
private:
    /// Tells if the object already found its value in the settings map.
    bool has_value;
    /// The current value and the default value.
    T value, default_value;
    /// The tag and full help strings.
    std::string tag, help_str;
};

typedef std::map<std::string, std::string> SettingsMap;

/**
 * The main function used for parsing the command line arguments.
 *
 * @param argc The number of arguments.
 * @param argv The command line arguments.
 */
void main(int argc, char *argv[]);

/**
 * @return The full help menu string for all declared Value objects.
 */
std::string getHelpString();

/**
 * Get a boolean value from the parsed arguments. When successful, this
 * function sets the value of the second parameter and returns true.
 *
 * @param tag The tag used to find the argument.
 * @param value The returned value (if successful) from the argument list.
 * @return True if the argument was found and was a boolean.
 */
bool getBoolFromArgs(const std::string& tag, bool& value);

/**
 * Get an integer value from the parsed arguments. When successful, this
 * function sets the value of the second parameter and returns true.
 *
 * @param tag The tag used to find the argument.
 * @param value The returned value (if successful) from the argument list.
 * @return True if the argument was found and was an integer.
 */
bool getIntFromArgs(const std::string& tag, int& value);

/**
 * Get a string value from the parsed arguemnts. When successful, this
 * function sets the value of the second parameter and returns true.
 *
 * @param tag The tag used to find the argument.
 * @param value The returned value (if successful) from the argument list.
 * @return True if the argument was found.
 */
bool getStringFromArgs(const std::string& tag, std::string& value);

} // namespace settings
} // namespace uv

#endif // __UVSETTINGS_H
